package org.llc.oauthclient.config;

import lombok.extern.slf4j.Slf4j;
import org.llc.oauthclient.config.jwt.CustomerAccessTokenConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.llc.common.starter.token.CustomRedisTokenStore;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.stream.Collectors;

/**
 * TokenStore配置类
 *
 * @author llc
 * @date 2020/1/10 16:25
 * @since 1.0.0
 */
@Slf4j
@Configuration
public class TokenStoreConfig {

    /**
     * redis
     */
    private final RedisTemplate<String, Object> redisTemplate;

    public TokenStoreConfig(
            @Autowired(required = false)
                    RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 使用redis方式存储token
     * <p>
     *     还是官方实现的更好用,刷新token后原token不可用，自己实现的这个地方尚未实现
     *     但是自己实现的customRedisTokenStore 可以自定义token存储内容
     * </p>
     *
     * @return com.bccv.nmg.server.token.RedisTemplateTokenStore
     * @author llc
     * @date 2020/1/20 13:41
     */
    @Bean
    @ConditionalOnProperty(prefix="security.oauth2.token-store",name="type" ,havingValue="redis" ,matchIfMissing=true)
    public RedisTokenStore redisTokenStore(){
        log.info("使用  --->  RedisTokenStore 存储token");
        return new RedisTokenStore(redisTemplate.getConnectionFactory());
    }

    /**
     * 使用redis方式存储token
     *
     * @return com.bccv.nmg.server.token.RedisTemplateTokenStore
     * @author llc
     * @date 2019/6/4 13:41
     */
    @Bean
    @ConditionalOnProperty(prefix = "security.oauth2.token-store", name = "type", havingValue = "redis-custom")
    public CustomRedisTokenStore customRedisTokenStore() {
        log.info("使用  --->  CustomRedisTokenStore 存储token");
        CustomRedisTokenStore customRedisTokenStore = new CustomRedisTokenStore();
        customRedisTokenStore.setRedisTemplate(redisTemplate);
        return customRedisTokenStore;
    }

    /**
     * JwtTokenStore配置类
     *
     * @author llc
     * @date 2020/1/10 16:25
     * @since 1.0.0
     */
    @Configuration
    @ConditionalOnProperty(prefix = "security.oauth2.token-store", name = "type", havingValue = "jwt")
    public static class JwtTokenConfig {

        /**
         * 配置TokenStore
         *
         * @return org.springframework.security.oauth2.provider.token.TokenStore
         * @author llc
         * @date 2020/1/13 16:29
         */
        @Bean
        @Qualifier("tokenStore")
        public TokenStore tokenStore() {
            log.info("使用  --->  JwtTokenStore 存储token");
            return new JwtTokenStore(accessTokenConverter());
        }

        /**
         * 资源服务token转换器
         *
         * @return org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter
         * @author llc
         * @date 2020/1/10 17:46
         */
        @Bean
        public JwtAccessTokenConverter accessTokenConverter() {
            log.info("Create --->  JwtAccessTokenConverter ");
            JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(new ClassPathResource("public.cert").getInputStream()))) {
                String publicKey = br.lines().collect(Collectors.joining("\n"));
                log.info("publicKey  -> {}", publicKey);
                converter.setVerifierKey(publicKey);
                // 替换默认的token生成方式
                converter.setAccessTokenConverter(new CustomerAccessTokenConverter());
            } catch (IOException e) {
                e.printStackTrace();
            }
            return converter;
        }
    }
}
